<template>
  <el-card>
    <el-row :gutter="6">
      <el-col :span="10">
        <el-card class="box-card">
          <template #header>
            <div class="card-header justify-between">
              <div class="text">角色列表</div>
              <div>
                <el-input
                  v-model="roleQuery.name"
                  placeholder="请输入角色名称"
                  clearable
                  size="small"
                  @keyup.enter="getRoleList"
                  width="100"
                />
                <el-button
                  type="primary"
                  size="small"
                  icon="Search"
                  @click="getRoleList"
                >
                  筛选
                </el-button>
              </div>
            </div>
          </template>
          <el-table
            row-class-name="table-row-selectable"
            v-loading="roleLoading"
            highlight-current-row
            :data="roleList"
            style="height: 59vh; width: 50vw"
            @row-click="handleRoleListClick"
          >
            <el-table-column prop="name" label="角色名" />
            <el-table-column prop="totalPeople" label="分配用户" />
            <el-table-column prop="createTime" label="创建时间" />
          </el-table>
          <!-- 分页组件 -->
          <pagination
            small
            v-show="roleTotal > 0"
            :total="roleTotal"
            v-model:page="roleQuery.pageNum"
            v-model:limit="roleQuery.pageSize"
            :layout="'prev, pager, next'"
            @pagination="getRoleList"
          />
        </el-card>
      </el-col>

      <el-col :span="12">
        <el-card class="box-card">
          <template #header>
            <div class="card-header justify-between">
              <div class="text">权限树</div>
              <div v-if="permissionTree.length > 0">
                <el-button
                  type="info"
                  plain
                  icon="Sort"
                  size="small"
                  @click="handleToggleExpandAll"
                >
                  展开/折叠
                </el-button>
                <el-button
                  type="primary"
                  @click="handleSavePermission"
                  size="small"
                >
                  保存
                </el-button>
                <el-button @click="handleReset" size="small">重置</el-button>
              </div>
            </div>
          </template>

          <el-scrollbar style="height: 70vh">
            <el-tree
              v-loading="isLoading"
              :data="permissionTree"
              show-checkbox
              node-key="id"
              :default-expand-all="false"
              :expand-on-click-node="true"
              :default-checked-keys="childPermissionIds"
              empty-text="暂无数据"
              ref="treeRef"
              @check="nodeClick"
            >
              <template #default="{ node, data }">
                <span class="custom-tree-node">
                  <span>{{ node.label }}</span>
                  <span class="setting">
                    <el-tooltip
                      content="更新角色可视字段"
                      placement="top"
                      :enterable="false"
                    >
                      <el-button
                        link
                        type="primary"
                        icon="View"
                        v-show="data.returnModelId && data.isChecked === true"
                        @click="viewSetting(data)"
                      ></el-button>
                    </el-tooltip>
                    <el-tooltip
                      content="更新角色可改字段"
                      placement="top"
                      :enterable="false"
                    >
                      <el-button
                        link
                        type="primary"
                        icon="Edit"
                        v-show="data.requestModelId && data.isChecked === true"
                        @click="updateSetting(data)"
                      ></el-button>
                    </el-tooltip>
                  </span>
                </span>
              </template>
            </el-tree>
          </el-scrollbar>
        </el-card>
      </el-col>
    </el-row>
    <!--      <el-tabs-->
    <!--        tab-position="left"-->
    <!--        style="height: 100vh"-->
    <!--        class="demo-tabs"-->
    <!--        type="border-card"-->
    <!--        @tab-click="tabChange"-->
    <!--      >-->
    <!--        <el-scrollbar style="height: 95vh">-->
    <!--          <el-tab-pane-->
    <!--            :name="(item as any).id"-->
    <!--            :label="(item as any).name"-->
    <!--            v-for="(item, index) in roleList"-->
    <!--            :key="index"-->
    <!--          >-->
    <!--            <el-tree-->
    <!--              v-loading="isLoading"-->
    <!--              :data="permissionTree"-->
    <!--              show-checkbox-->
    <!--              node-key="id"-->
    <!--              :default-expand-all="false"-->
    <!--              :expand-on-click-node="true"-->
    <!--              :default-checked-keys="childPermissionIds"-->
    <!--              empty-text="暂无数据"-->
    <!--              ref="treeRef"-->
    <!--              @check="nodeClick"-->
    <!--            >-->
    <!--              <template #default="{ node, data }">-->
    <!--                <span class="custom-tree-node">-->
    <!--                  <span>{{ node.label }}</span>-->
    <!--                  <span class="setting">-->
    <!--                    <el-tooltip-->
    <!--                      content="更新角色可视字段"-->
    <!--                      placement="top"-->
    <!--                      :enterable="false"-->
    <!--                    >-->
    <!--                      <el-button-->
    <!--                        link-->
    <!--                        type="primary"-->
    <!--                        icon="View"-->
    <!--                        v-show="data.returnModelId && data.isChecked === true"-->
    <!--                        @click="viewSetting(data)"-->
    <!--                      ></el-button>-->
    <!--                    </el-tooltip>-->
    <!--                    <el-tooltip-->
    <!--                      content="更新角色可改字段"-->
    <!--                      placement="top"-->
    <!--                      :enterable="false"-->
    <!--                    >-->
    <!--                      <el-button-->
    <!--                        link-->
    <!--                        type="primary"-->
    <!--                        icon="Edit"-->
    <!--                        v-show="data.requestModelId && data.isChecked === true"-->
    <!--                        @click="updateSetting(data)"-->
    <!--                      ></el-button>-->
    <!--                    </el-tooltip>-->
    <!--                  </span>-->
    <!--                </span>-->
    <!--              </template>-->
    <!--            </el-tree>-->
    <!--            <div style="margin: 10px 0 0 10vw">-->
    <!--              <el-button-->
    <!--                type="primary"-->
    <!--                @click="handleSavePermission"-->
    <!--                size="small"-->
    <!--              >-->
    <!--                保存-->
    <!--              </el-button>-->
    <!--              <el-button @click="handleReset" size="small">取消</el-button>-->
    <!--            </div>-->
    <!--          </el-tab-pane>-->
    <!--        </el-scrollbar>-->
    <!--      </el-tabs>-->
  </el-card>

  <!-- 设置字段对话框 -->
  <el-dialog
    v-model="dialogStatus.isVisible"
    :title="dialogStatus.title"
    width="40%"
    center
    append-to-body
    :show-close="false"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
  >
    <el-checkbox
      v-model="checkAll"
      :indeterminate="isIndeterminate"
      @change="handleCheckAllChange"
    >
      全选
    </el-checkbox>
    <el-checkbox-group v-model="currentFields">
      <el-checkbox
        v-for="item in fields"
        :key="(item as any).id"
        :label="(item as any).name"
        @change="handleCheckedCitiesChange"
        border
      >
        {{ (item as any).displayName }}
      </el-checkbox>
    </el-checkbox-group>
    <div style="margin: 20px 0 0 24vw">
      <el-button
        type="primary"
        icon="Search"
        @click="innerDialogSubmit"
        v-hasPermi="['system:role:edit']"
      >
        保存
      </el-button>
      <el-button icon="Search" @click="handleCloseDialog">取消</el-button>
    </div>
  </el-dialog>
</template>

<script setup lang="ts">
import {
  getFields as getFieldsApi,
  getPermissionTree as getPermissionTreeApi,
  getRoleList as getRoleListApi,
  getRolePermission as getRolePermissionApi,
  getSavedFields as getSavedFieldsApi,
  savePermission as savePermissionApi,
} from "@/service/api/system/rolePermission";
import to from "await-to-js";
import {
  PermissionNode,
  SysFieldVo,
  SysModelVo,
  SysRoleVo,
} from "@/service/api/system/rolePermission/types.ts";
import { BasePageResponse, BaseResponse } from "@/service/api/type.ts";
import { ElTable } from "element-plus";
import Pagination from "@/components/Pagination/index.vue";
import {removeButtonFocus} from "@/utils/focus.tsx";

// dialog
const initDialogStatus = {
  isVisible: false,
  title: "",
};
/**
 * 角色查询参数
 */
const roleQuery = ref({
  name: "",
  superAdmin: false,
  pageSize: 10,
  pageNum: 1,
  orderByColumn: "createTime",
  orderType: "desc",
});

const roleLoading = ref<boolean>(false);
const permissionLoading = ref<boolean>(false);
const isExpandAll = ref(false);
const treeRef = ref(ElTable);

// 页面数据
const pageData = reactive({
  permissionTree: <PermissionNode[]>[],
  roleTotal: 0,
  roleList: <SysRoleVo[]>[],
  filterPermissionIds: [],
  dialogStatus: { ...initDialogStatus },
});

const { permissionTree, roleTotal, roleList, dialogStatus } = toRefs(pageData);
const isLoading = ref(false);
// 当前角色id
const currentRoleId = ref();
// 是否全选
const checkAll = ref(false);
// 是否半选
const isIndeterminate = ref(false);
// 已勾选数组
const finalNodes: any = ref([]);
// 所有字段
const fields = ref<SysFieldVo[]>([]);
// 后台已勾选的子节点
// 角色已勾选的权限
const childPermissionIds = ref<string[]>([]);
const permissionIds = ref<string[]>([]);
// 当前勾选的字段数组
const currentFields = ref<string[]>([]);
// 当前点击的节点id
const currentPermissionId = ref("");

/**
 * 选中用户列表
 */
const handleRoleListClick = async (row: any) => {
  permissionLoading.value = true;
  currentRoleId.value = row.id;

  getCurrentRolePermission();
};

/**
 * 获取当前角色权限信息
 */
const getCurrentRolePermission = async(): Promise<boolean> => {
  const [err, res] = await to<BaseResponse<SysRoleVo>, any>(
      getRolePermissionApi(currentRoleId.value),
  );
  if (!err) {
    console.log(res?.data);
    // 按钮和接口选中的id列表（只包含子节点）
    childPermissionIds.value = res?.data?.sonIdList ?? [];
    // 所有选中的权限id列表（包含父节点）
    permissionIds.value = res?.data?.permissionIds ?? [];
    isLoading.value = false;
    return await getPermissionTree();
  }

  isLoading.value = false;
  return false;
}

/**
 * 获取角色列表，不泄漏异常
 */
const getRoleList = async (): Promise<boolean> => {
  const [err, res] = await to<BasePageResponse<SysRoleVo>, any>(
    getRoleListApi(roleQuery.value),
  );
  if (!err) {
    roleList.value = res?.rows ?? [];
    roleTotal.value = Number(res?.total ?? 0);
    console.log(roleList.value);
    return true;
  }
  return false;
};

/**
 * 获取权限树（无勾选状态），不泄露异常
 */
const getPermissionTree = async (): Promise<boolean> => {
  const [err, res] = await to<BaseResponse<PermissionNode[]>, any>(
    getPermissionTreeApi(),
  );
  if (!err) {
    permissionTree.value = res?.data ?? [];
    console.log(permissionTree.value);
    setDefaultChecked(permissionTree.value);
    return true;
  }
  return false;
  // const ids = getRootIds(permissionTree.value);
  // console.log(ids.length);
};

/**
 * 初次渲染设置选中状态
 * @param treeArr
 */
const setDefaultChecked = (treeArr: any) => {
  for (let i = 0; i < treeArr.length; i++) {
    let node = treeArr[i];
    // 遍历每个节点并且设置为已勾选
    node.isChecked = permissionIds.value.some((item) => item === node.id);
    if (node.children && node.children.length > 0) {
      setDefaultChecked(node.children);
    }
  }
};

/**
 * 遍历permissionTree,设置已勾选的为true
 * @param treeArr
 */
const setDynamicChecked = (treeArr: any) => {
  for (let i = 0; i < treeArr.length; i++) {
    const node = treeArr[i];
    // 找到已勾选列表是否有
    // 有就勾上 没有就不勾
    node.isChecked = checkedNodes.value.some((item: any) => {
      return item.id === node.id;
    });
    if (node.children && node.children.length > 0) {
      setDynamicChecked(node.children); // 递归调用，处理每个子节点
    }
  }
};

/**
 * 在tree中找到该节点并赋值
 * @param treeArr
 * @param permissionId
 */
const setEditFields = (treeArr: any, permissionId: string) => {
  for (let i = 0; i < treeArr.length; i++) {
    let node = treeArr[i];
    if (node.id === permissionId) {
      node.editableFields.fields = currentFields.value;
    }
    if (node.children && node.children.length > 0) {
      setEditFields(node.children, permissionId); // 递归调用，处理每个子节点
    }
  }
};
/**
 * 在tree中找到该节点并赋值
 * @param treeArr
 * @param permissionId
 */
const setVisFields = (treeArr: any, permissionId: string) => {
  for (let i = 0; i < treeArr.length; i++) {
    let node = treeArr[i];
    if (node.id === permissionId) {
      node.visibleFields.fields = currentFields.value;
    }
    if (node.children && node.children.length > 0) {
      setVisFields(node.children, permissionId); // 递归调用，处理每个子节点
    }
  }
};

/**
 * 遍历拿到树形节点中所有选中的节点
 * @param treeArr
 */
const getCheckedNodes = (treeArr: any) => {
  for (let i = 0; i < treeArr.length; i++) {
    let node = treeArr[i];
    if (node.isChecked) {
      console.log(node);
      node.permissionId = node.id;
      finalNodes.value.push(node as object);
    } else {
      node.isChecked = false;
    }
    if (node.children && node.children.length > 0) {
      getCheckedNodes(node.children); // 递归调用，处理每个子节点
    }
  }
};

// 所有已选择的node
const checkedNodes: any = ref([]);

/**
 * 复选框被点击
 * @param node
 * @param status
 */
const nodeClick = async (node: any, status: any) => {
  // 保存已勾选的节点
  console.log(node);

  checkedNodes.value = [
    ...JSON.parse(JSON.stringify(status.checkedNodes)),
    ...JSON.parse(JSON.stringify(status.halfCheckedNodes)),
  ];
  console.log(permissionTree.value, checkedNodes.value);

  setDynamicChecked(permissionTree.value);
};

/**
 * 处理权限保存
 */
const handleSavePermission = async () => {
  const [err, confirm] = await to<string, string>(
    ElMessageBox.confirm("是否确定要保存所有权限?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    }),
  );
  if (err === "cancel") {
    ElMessage({
      type: "info",
      message: "取消保存",
    });
  } else if (confirm === "confirm") {
    getCheckedNodes(permissionTree.value);
    const [err2, res2] = await to<BaseResponse<any>, any>(
      savePermissionApi(currentRoleId.value, finalNodes.value),
    );
    if (!err2) {
      console.log(res2);
      ElMessage({
        type: "success",
        message: "保存成功",
      });
    } else {
      console.log(err2);
      console.log(finalNodes.value, permissionTree.value);
    }
    finalNodes.value = [];
    // 刷新
    getCurrentRolePermission();
  }
};

/**
 * 处理展开折叠
 */
const handleToggleExpandAll = (event: MouseEvent) => {
  isExpandAll.value = !isExpandAll.value;
  let nodes = treeRef.value.store.nodesMap;
  for (const node in nodes) {
    nodes[node].expanded = isExpandAll.value;
  }
  removeButtonFocus(event);
};

/**
 * 处理重置按钮
 */
const handleReset = async () => {
  const [err, confirm] = await to<string, string>(
    ElMessageBox.confirm("是否删除所有操作回到初始状态?", "提示", {
      confirmButtonText: "是",
      cancelButtonText: "否",
      type: "warning",
    }),
  );
  if (err === "cancel") {
    ElMessage({
      type: "info",
      message: "取消重置，所有勾选依然处于未保存状态",
    });
  } else if (confirm === "confirm") {
    const response = await getCurrentRolePermission();
    if (response) {
      ElMessage({
        type: "success",
        message: "重置成功",
      });
    }
  }
};

/**
 * 设置可视字段
 * @param data
 */
const viewSetting = async (data: any) => {
  // 获取该节点所有字段
  currentPermissionId.value = data.id;
  const [err, res] = await to<BaseResponse<SysModelVo>, any>(
    getFieldsApi(data.returnModelId),
  );
  console.log(res);
  if (!err) {
    fields.value = res?.data?.fields ?? [];
    // 要添加的临时参数
    const visibleFields = {
      modelId: data.returnModelId,
      fields: [],
    };

    if (data.visibleFields) {
      // 如果已经有了则说明设置过
      currentFields.value = data.visibleFields.fields;
    } else {
      // 给节点加上这个字段
      data.visibleFields = visibleFields;
      // 发请求获取后台已勾选的
      // 获取已勾选的BO
      const currentQueryData = {
        roleId: currentRoleId.value,
        permissionId: data.id,
      };
      const [err, res2] = await to<BaseResponse<SysModelVo>, any>(
        getSavedFieldsApi(currentQueryData),
      );
      if (!err) {
        console.log(res2?.data);
        currentFields.value = res2?.data?.visibleFields?.fields ?? [];
        // 将后台给的数据放入节点
        data.visibleFields.fields = currentFields.value;
      }
    }

    // 已选字段
    checkAll.value = currentFields.value.length === fields.value.length;
    isIndeterminate.value =
      currentFields.value.length > 0 &&
      currentFields.value.length < fields.value.length;
    dialogStatus.value.isVisible = true;
    dialogStatus.value.title = "修改可视字段";
  }
};

/**
 * 设置可改字段
 * @param data
 */
const updateSetting = async (data: any) => {
  // 获取该节点所有字段
  console.log(permissionTree.value);
  currentPermissionId.value = data.id;
  const [err, res] = await to<BaseResponse<SysModelVo>, any>(
    getFieldsApi(data.requestModelId),
  );
  if (!err) {
    console.log(res);
    fields.value = res?.data?.fields ?? [];
    console.log(fields.value);

    // 要添加的临时参数
    const editableFields = {
      modelId: data.requestModelId,
      fields: [],
    };

    if (data.editableFields) {
      // 如果已经有了则说明设置过
      currentFields.value = data.editableFields.fields;
    } else {
      // 给节点加上这个字段
      data.editableFields = editableFields;
      // 获取已勾选的BO

      const currentQueryData = {
        roleId: currentRoleId.value,
        permissionId: data.id,
      };
      // 发请求获取后台已勾选的

      const [err, res2] = await to<BaseResponse<SysModelVo>, any>(
        getSavedFieldsApi(currentQueryData),
      );
      if (!err) {
        console.log(res2?.data);
        currentFields.value = res2?.data?.editableFields?.fields ?? [];
        // 将后台给的数据放入节点
        data.editableFields.fields = currentFields.value;
      }
    }
  }

  // 已选字段
  checkAll.value = currentFields.value.length === fields.value.length;
  isIndeterminate.value =
    currentFields.value.length > 0 &&
    currentFields.value.length < fields.value.length;
  dialogStatus.value.isVisible = true;
  dialogStatus.value.title = "修改可改字段";
};

/**
 * 全选按钮
 * @param val
 */
const handleCheckAllChange = (val: boolean) => {
  console.log(val);
  const tempFields = val ? fields.value : [];
  isIndeterminate.value = false;
  // 过滤出只有name字段的数组
  currentFields.value = tempFields.map((item: any) => item.name);
  console.log(currentFields.value);
};

/**
 * 选中按钮
 */
const handleCheckedCitiesChange = () => {
  console.log(permissionTree.value);
  checkAll.value = currentFields.value.length === fields.value.length;
  isIndeterminate.value =
    currentFields.value.length > 0 &&
    currentFields.value.length < fields.value.length;
};

/**
 * 对话框保存
 */
const innerDialogSubmit = async () => {
  // 保存勾选的字段
  console.log(permissionTree.value);
  if (dialogStatus.value.title === "修改可视字段") {
    setVisFields(permissionTree.value, currentPermissionId.value);
  } else {
    setEditFields(permissionTree.value, currentPermissionId.value);
  }
  dialogStatus.value = Object.assign({}, initDialogStatus);
};

/**
 * 关闭对话框
 */
const handleCloseDialog = () => {
  dialogStatus.value = Object.assign({}, initDialogStatus);
};

onMounted(() => {
  getPermissionTree();
  getRoleList();
});
</script>

<style scoped>
.card-header {
  display: flex;

  .text {
    width: 150px;
    /* background-color: aqua; */
  }

  .el-input {
    margin: 0 5px 0 0;
    width: 200px;
  }
}

.el-tabs--right .el-tabs__content,
.el-tabs--left .el-tabs__content {
  height: 100%;
}

.custom-tree-node {
  flex: 1;
  /* display: flex; */
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;

  .setting {
    margin: 0 0 10px 10px;
  }
}
</style>
